Readings: Stewart et al.
Lots of contemporary neural models are quite simple
What happens when our models get more complex?
One group of neurons for each action's utility $Q(s, a_i)$
What should the output be?
Do action A if $s$ is near [1,0], B if near [-1,0], C if near [0,1], D if near [0,-1]
REMINDER: COURSE EVALUATION STUFF!
In [3]:
%pylab inline
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [np.sin(t), np.cos(t)])
s = nengo.Ensemble(200, dimensions=2)
Q_A = nengo.Ensemble(50, dimensions=1)
Q_B = nengo.Ensemble(50, dimensions=1)
Q_C = nengo.Ensemble(50, dimensions=1)
Q_D = nengo.Ensemble(50, dimensions=1)
nengo.Connection(s, Q_A, transform=[[1,0]])
nengo.Connection(s, Q_B, transform=[[-1,0]])
nengo.Connection(s, Q_C, transform=[[0,1]])
nengo.Connection(s, Q_D, transform=[[0,-1]])
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qa_p = nengo.Probe(Q_A)
qb_p = nengo.Probe(Q_B)
qc_p = nengo.Probe(Q_C)
qd_p = nengo.Probe(Q_D)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(3.)
In [4]:
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure(figsize=(8,8))
plot(t, sim.data[qa_p], label='Q_A')
plot(t, sim.data[qb_p], label='Q_B')
plot(t, sim.data[qc_p], label='Q_C')
plot(t, sim.data[qd_p], label='Q_D')
legend(loc='best');
That behavior makes a lot of sense
It's annoying to have all those separate $Q$ neurons
In [5]:
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [np.sin(t), np.cos(t)])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(3.)
In [6]:
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure(figsize=(8,8))
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best');
Yay, Network Arrays make shorter code!
Back to the model: How do we implement the $max$ function?
In [7]:
import nengo
def maximum(x):
result = [0,0,0,0]
result[np.argmax(x)] = 1
return result
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [np.sin(t), np.cos(t)])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Qall = nengo.Ensemble(400, dimensions=4)
Action = nengo.Ensemble(200, dimensions=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Qall)
nengo.Connection(Qall, Action, function=maximum)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(3.)
In [8]:
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best');
In [9]:
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [.5,.4] if t <1. else [0,0] )
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
e = 0.1
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
nengo.Connection(Qs.output, Qs.input, transform=recur)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(1.)
In [10]:
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best');
In [10]:
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [.5,.4] if t <1. else [0,0] )
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = 0.1
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
# Let's force the feedback connection to only consider positive values
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(1.)
In [11]:
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend(loc='best')
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best');
e
?
In [12]:
%pylab inline
import nengo
def stimulus(t):
if t<.3:
return [.5,.4]
elif .3<t<.5:
return [.4,.5]
else:
return [0,0]
model = nengo.Network('Selection')
with model:
stim = nengo.Node(stimulus)
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = .5
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
# Let's force the feedback connection to only consider positive values
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
s_p = nengo.Probe(s)
In [13]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/action_selection.py.cfg")
In [14]:
sim = nengo.Simulator(model)
sim.run(1.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend(loc='best')
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best');
e
too much?
In [15]:
%pylab inline
import nengo
def stimulus(t):
if t<.3:
return [.5,.4]
elif .3<t<.5:
return [.3,.5]
else:
return [0,0]
model = nengo.Network('Selection')
with model:
stim = nengo.Node(stimulus)
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = 0.2
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
def select(x):
if x[0]>=0: return [1]
else: return [0]
sel = Action.add_output('select', select)
aValues = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(sel, aValues.input)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
aValues_p = nengo.Probe(aValues.output)
s_p = nengo.Probe(s)
In [14]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/action_selection2.py.cfg")
In [16]:
sim = nengo.Simulator(model)
sim.run(1.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend(loc='best')
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best')
figure()
plot(t, sim.data[aValues_p], label='Action Values')
legend(loc='best');
e
In [17]:
%pylab inline
import nengo
def stimulus(t):
if t<.3:
return [.5,.4]
elif .3<t<.5:
return [.3,.5]
else:
return [0,0]
model = nengo.Network('Selection')
with model:
stim = nengo.Node(stimulus)
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = 0.1
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
def select(x):
if x[0]>=0: return [1]
else: return [0]
sel = Action.add_output('select', select)
aValues = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(sel, aValues.input)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
aValues_p = nengo.Probe(aValues.output)
s_p = nengo.Probe(s)
#sim = nengo.Simulator(model)
#sim.run(1.)
In [18]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_simple1.py.cfg")
And this gets harder to balance as the number of actions increases
But this is still a pretty standard approach
They tend to use a "kWTA" (k-Winners Take All) approach in their models
Any other options?
Activity in the GPi (output)
Leabra approach
In [64]:
%pylab inline
mm=1
mp=1
me=1
mg=1
#connection strengths from original model
ws=1
wt=1
wm=1
wg=1
wp=0.9
we=0.3
#neuron lower thresholds for various populations
e=0.2
ep=-0.25
ee=-0.2
eg=-0.2
le=0.2
lg=0.2
D = 10
tau_ampa=0.002
tau_gaba=0.008
N = 50
radius = 1.5
import nengo
from nengo.dists import Uniform
model = nengo.Network('Basal Ganglia', seed=4)
with model:
stim = nengo.Node([0]*D)
StrD1 = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(e,1),
encoders=Uniform(1,1), radius=radius)
StrD2 = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(e,1),
encoders=Uniform(1,1), radius=radius)
STN = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(ep,1),
encoders=Uniform(1,1), radius=radius)
GPi = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(eg,1),
encoders=Uniform(1,1), radius=radius)
GPe = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(ee,1),
encoders=Uniform(1,1), radius=radius)
nengo.Connection(stim, StrD1.input, transform=ws*(1+lg), synapse=tau_ampa)
nengo.Connection(stim, StrD2.input, transform=ws*(1-le), synapse=tau_ampa)
nengo.Connection(stim, STN.input, transform=wt, synapse=tau_ampa)
def func_str(x): #relu-like function
if x[0]<e: return 0
return mm*(x[0]-e)
strd1_out = StrD1.add_output('func_str', func_str)
strd2_out = StrD2.add_output('func_str', func_str)
nengo.Connection(strd1_out, GPi.input, transform=-wm, synapse=tau_gaba)
nengo.Connection(strd2_out, GPe.input, transform=-wm, synapse=tau_gaba)
def func_stn(x):
if x[0]<ep: return 0
return mp*(x[0]-ep)
stn_out = STN.add_output('func_stn', func_stn)
tr=[[wp]*D for i in range(D)]
nengo.Connection(stn_out, GPi.input, transform=tr, synapse=tau_ampa)
nengo.Connection(stn_out, GPe.input, transform=tr, synapse=tau_ampa)
def func_gpe(x):
if x[0]<ee: return 0
return me*(x[0]-ee)
gpe_out = GPe.add_output('func_gpe', func_gpe)
nengo.Connection(gpe_out, GPi.input, transform=-we, synapse=tau_gaba)
nengo.Connection(gpe_out, STN.input, transform=-wg, synapse=tau_gaba)
Action = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=tau_gaba)
def func_gpi(x):
if x[0]<eg: return 0
return mg*(x[0]-eg)
gpi_out = GPi.add_output('func_gpi', func_gpi)
nengo.Connection(gpi_out, Action.input, transform=-3, synapse=tau_gaba)
In [65]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_good2.py.cfg")
Notice that we are also flipping the output from [1, 1, 0, 1] to [0, 0, 1, 0]
Works pretty well
Dynamic Behaviour of a Spiking Model of Action Selection in the Basal Ganglia
Let's make sure this works with our original system
In [19]:
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network(label='Selection')
D=4
with model:
stim = nengo.Node([0,0])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=D)
nengo.Connection(stim, s)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
In [67]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_good1.py.cfg")
In [35]:
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network(label='Selection')
D=4
with model:
stim = nengo.Node([0,0])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(stim, s)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
motor = nengo.Ensemble(100, dimensions=2)
nengo.Connection(Action.output[0], motor, transform=[[1],[0]])
nengo.Connection(Action.output[1], motor, transform=[[-1],[0]])
nengo.Connection(Action.output[2], motor, transform=[[0],[1]])
nengo.Connection(Action.output[3], motor, transform=[[0],[-1]])
In [36]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_good3.py.cfg")
In [8]:
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network('Creature')
with model:
stim = nengo.Node([0,0], label='stim')
command = nengo.Ensemble(100, dimensions=2, label='command')
motor = nengo.Ensemble(100, dimensions=2, label='motor')
position = nengo.Ensemble(1000, dimensions=2, label='position')
scared_direction = nengo.Ensemble(100, dimensions=2, label='scared direction')
def negative(x):
return -x[0], -x[1]
nengo.Connection(position, scared_direction, function=negative)
nengo.Connection(position, position, synapse=.05)
def rescale(x):
return x[0]*0.1, x[1]*0.1
nengo.Connection(motor, position, function=rescale)
nengo.Connection(stim, command)
D=4
Q_input = nengo.Node([0,0,0,0], label='select')
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(Q_input, Qs.input)
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
do_command = nengo.Ensemble(300, dimensions=3, label='do command')
nengo.Connection(command, do_command[0:2])
nengo.Connection(Action.output[0], do_command[2])
def apply_command(x):
return x[2]*x[0], x[2]*x[1]
nengo.Connection(do_command, motor, function=apply_command)
do_scared = nengo.Ensemble(300, dimensions=3, label='do scared')
nengo.Connection(scared_direction, do_scared[0:2])
nengo.Connection(Action.output[1], do_scared[2])
nengo.Connection(do_scared, motor, function=apply_command)
In [9]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_creature.py.cfg")
#first dimensions activates do_command, i.e. go in the indicated direciton
#second dimension activates do_scared, i.e. return 'home' (0,0)
#creature tracks the position it goes to (by integrating)
#creature inverts direction to position via scared direction/do_scared and puts that into motor
In [6]:
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network('Creature')
with model:
stim = nengo.Node([0,0], label='stim')
command = nengo.Ensemble(100, dimensions=2, label='command')
motor = nengo.Ensemble(100, dimensions=2, label='motor')
position = nengo.Ensemble(1000, dimensions=2, label='position')
scared_direction = nengo.Ensemble(100, dimensions=2, label='scared direction')
def negative(x):
return -x[0], -x[1]
nengo.Connection(position, scared_direction, function=negative)
nengo.Connection(position, position, synapse=.05)
def rescale(x):
return x[0]*0.1, x[1]*0.1
nengo.Connection(motor, position, function=rescale)
nengo.Connection(stim, command)
D=4
Q_input = nengo.Node([0,0,0,0], label='select')
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(Q_input, Qs.input)
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
do_command = nengo.Ensemble(300, dimensions=2, label='do command')
nengo.Connection(command, do_command)
nengo.Connection(Action.output[1], do_command.neurons, transform=-np.ones([300,1]))
nengo.Connection(do_command, motor)
do_scared = nengo.Ensemble(300, dimensions=2, label='do scared')
nengo.Connection(scared_direction, do_scared)
nengo.Connection(Action.output[0], do_scared.neurons, transform=-np.ones([300,1]))
nengo.Connection(do_scared, motor)
In [7]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_creature2.py.cfg")
We build systems in cortex that give some input-output functionality
Example
In [41]:
%pylab inline
import nengo
from nengo import spa
D = 16
def start(t):
if t < 0.05:
return 'A'
else:
return '0'
model = spa.SPA(label='Sequence_Module', seed=5)
with model:
model.cortex = spa.Buffer(dimensions=D, label='cortex')
model.input = spa.Input(cortex=start, label='input')
actions = spa.Actions(
'dot(cortex, A) --> cortex = B',
'dot(cortex, B) --> cortex = C',
'dot(cortex, C) --> cortex = D',
'dot(cortex, D) --> cortex = E',
'dot(cortex, E) --> cortex = A'
)
model.bg = spa.BasalGanglia(actions=actions)
model.thal = spa.Thalamus(model.bg)
cortex = nengo.Probe(model.cortex.state.output, synapse=0.01)
actions = nengo.Probe(model.thal.actions.output, synapse=0.01)
utility = nengo.Probe(model.bg.input, synapse=0.01)
sim = nengo.Simulator(model)
sim.run(0.5)
In [42]:
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_alphabet.py.cfg")
In [43]:
fig = figure(figsize=(12,8))
p1 = fig.add_subplot(3,1,1)
p1.plot(sim.trange(), model.similarity(sim.data, cortex))
p1.legend(model.get_output_vocab('cortex').keys, fontsize='x-small')
p1.set_ylabel('State')
p2 = fig.add_subplot(3,1,2)
p2.plot(sim.trange(), sim.data[actions])
p2_legend_txt = [a.effect for a in model.bg.actions.actions]
p2.legend(p2_legend_txt, fontsize='x-small')
p2.set_ylabel('Action')
p3 = fig.add_subplot(3,1,3)
p3.plot(sim.trange(), sim.data[utility])
p3_legend_txt = [a.condition for a in model.bg.actions.actions]
p3.legend(p3_legend_txt, fontsize='x-small')
p3.set_ylabel('Utility')
fig.subplots_adjust(hspace=0.2)
What about behavioural evidence?
A few sources of support
In [7]:
from IPython.display import YouTubeVideo
YouTubeVideo('sUvHCs5y0o8', width=640, height=390, loop=1, autoplay=0)
Out[7]:
State:
goal
: what disk am I trying to move (D0, D1, D2)focus
: what disk am I looking at (D0, D1, D2)goal_peg
: where is the disk I am trying to move (A, B, C)focus_peg
: where is the disk I am looking at (A, B, C)target_peg
: where am I trying to move a disk to (A, B, C)goal_final
: what is the overall final desired location of the disk I'm trying to move (A, B, C)Note: we're not yet modelling all the sensory and memory stuff (e.g. loading) here, so we manually set things like goal_final
.
Action effects: when an action is selected, it could do the following
focus
goal
goal_peg
move
and move_peg
Is this sufficient to implement the algorithm described above?
focus
=NONE then focus
=D2, goal
=D2, goal_peg
=goal_final
focus
$\cdot$ NONE focus
=D2 and goal
=D2 and goal_peg
!=target_peg
then focus
=D1focus
$\cdot$ D2 + goal
$\cdot$ D2 - goal_peg
$\cdot$ target_peg
focus
=D2 and goal
=D2 and goal_peg
==target_peg
then focus
=D1, goal
=D1, goal_peg
=goal_final
focus
=D1 and goal
=D1 and goal_peg
!=target_peg
then focus
=D0focus
=D1 and goal
=D1 and goal_peg
==target_peg
then focus
=D0, goal
=D0, goal_peg
=goal_final
focus
=D0 and goal_peg
==target_peg
then focus
=NONEfocus
=D0 and goal
=D0 and goal_peg
!=target_peg
then focus
=NONE, move
=D0, move_peg
=target_peg
focus
!=goal
and focus_peg
==goal_peg
and target_peg!=focus_peg
then goal
=focus
, goal_peg
=A+B+C-target_peg
-focus_peg
focus
!=goal
and focus_peg
!=goal_peg
and target_peg==focus_peg
then goal
=focus
, goal_peg
=A+B+C-target_peg
-goal_peg
focus
=D0 and goal
!=D0 and target_peg
!=focus_peg
and target_peg
!=goal_peg
and focus_peg
!=goal_peg
then move
=goal
, move_peg
=target_peg
focus
=D1 and goal
!=D1 and target_peg
!=focus_peg
and target_peg
!=goal_peg
and focus_peg
!=goal_peg
then focus
=D0Do science
Timing:
In [ ]: